package com.auz.datagenerator.publishing.tcpip;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import com.auz.datagenerator.publishing.IPublisher;

/**
 * Server publishing heuristic. The generated values are published on a server running locally
 * and accessible using the implemented client <code>com.auz.datagenerator.publishing.
 * tcpip.client</code>.
 * @param <X> - the generic attribute for the server
 * @author Aurelien Bonnel
 */
public class Server<X> extends Thread implements IPublisher<X> {

	public final int DEFAULT_PORT = 50625;
	
	Logger logger = Logger.getLogger("TCPServer");
	private List<ServerThread<X>> threads;
	private ServerSocket service;
	private Socket clientSocket;
	private boolean pause;

	/**
	 * Constructor
	 */
	public Server() {
		try {
			service = new ServerSocket(DEFAULT_PORT);
			System.out.println("Server launched on " + service.getInetAddress().getCanonicalHostName());
			threads = new ArrayList<ServerThread<X>>();
		} catch (IOException e) {
			logger.severe("Server could not instantiate: " + e.getMessage());
			e.printStackTrace();
		}
	}

	/**
	 * Run the server as a separate thread
	 */
	public void run() {
		try {
			while(true) {
				clientSocket = service.accept();
				logger.info("Client registering...");
				ServerThread<X> newOne = new ServerThread<X>(clientSocket);
				threads.add(newOne);
				new Thread(newOne).start();
			}
		} catch (IOException e) {
			logger.severe("Server could not listen for connections: " + e.getMessage());
			e.printStackTrace();
		}
	}

	/**
	 * Halts the server
	 */
	public void halt() {
		try {
			for(ServerThread<X> current : threads) {
				current.halt();
			}
			clientSocket.close();
			service.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Pause the publishing from this server. The server/client connections will nonetheless
	 * still be active
	 */
	public void pause() {
		pause = true;
	}

	/**
	 * Publish the data
	 * @param _x - the object to publish
	 */
	public void publish(X _x) {
		try {
			if(! pause) {
				logger.info("Sending: " + _x.toString());
				for(ServerThread<X> current : threads) {
					current.publish(_x);
				}
			}
		} catch(Throwable t) {
			t.printStackTrace();
		}
	}

	/**
	 * Unpause the publishing
	 */
	public void unpause() {
		pause = false;
	}

}
